﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using DynORM.Interfaces;

namespace DynORM.ValueObjects
{

    public class AuxTypes
    {
        //auxiliary methods
        public static bool IsCLRTypeNullable(Type type)
        {
            return (type.Name == typeof(Nullable<>).Name || type == typeof(string));
        }

        public static Type GetCLRNullableType(Type type)
        {
            if (IsCLRTypeNullable(type) == false)
                return (typeof(System.Nullable<>)).MakeGenericType(type);
            else
                return type;
        }

        public static IEnumerable<Type> GetCLRCompatibleTypes(Type type)
        { 
            List<Type> result = new List<Type>();
            //including corresponding nullable types if type nullable
            //and self
            result.Add(type);

            bool isNullableStructure; 

            if (IsCLRTypeNullable(type) && type != typeof(string))
            {
                type = type.GetGenericArguments().First<Type>();
                isNullableStructure = true;
            }
            else
                isNullableStructure = false;

            if (type == typeof(Int16))
            {
                if (isNullableStructure)
                {
                    result.Add(typeof(Single?));
                    result.Add(typeof(Double?));
                    result.Add(typeof(Int32?));
                    result.Add(typeof(Int64?));
                }
                else
                {
                    result.Add(typeof(Single));
                    result.Add(typeof(Double));
                    result.Add(typeof(Int32));
                    result.Add(typeof(Int64));
                    result.Add(typeof(Single?));
                    result.Add(typeof(Double?));
                    result.Add(typeof(Int16?));
                    result.Add(typeof(Int32?));
                    result.Add(typeof(Int64?));
                }
            }
            if (type == typeof(Int32))
            {
                if (isNullableStructure)
                {
                    result.Add(typeof(Single?));
                    result.Add(typeof(Double?));
                    result.Add(typeof(Int64?));
                }
                else
                {
                    result.Add(typeof(Single));
                    result.Add(typeof(Double));
                    result.Add(typeof(Int64));
                    result.Add(typeof(Single?));
                    result.Add(typeof(Double?));
                    result.Add(typeof(Int32?));
                    result.Add(typeof(Int64?));
                }
            }
            if (type == typeof(Int64))
            {
                if (isNullableStructure)
                {
                    result.Add(typeof(Single?));
                    result.Add(typeof(Double?));
                }
                else
                {
                    result.Add(typeof(Single));
                    result.Add(typeof(Double));
                    result.Add(typeof(Single?));
                    result.Add(typeof(Double?));
                    result.Add(typeof(Int64?));
                }
            }
            if (type == typeof(Single))
            {
                if (isNullableStructure)
                {
                    result.Add(typeof(Double?));
                }
                else
                { 
                    result.Add(typeof(Double));
                    result.Add(typeof(Single?));
                    result.Add(typeof(Double?));
                }
            }
            if (type == typeof(Double) && (!isNullableStructure))
                result.Add(typeof(Double?));
            if (type == typeof(Decimal) && (!isNullableStructure))
                result.Add(typeof(Decimal?));
            if (type == typeof(DateTime) && (!isNullableStructure))
                result.Add(typeof(DateTime?));
            if (type == typeof(Guid) && (!isNullableStructure))
                result.Add(typeof(Guid?));
            if (type == typeof(Boolean) && (!isNullableStructure))
                result.Add(typeof(Boolean?));

            return result;
        }
    }
}
